home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
System Booster
/
System Booster.iso
/
Texteditors
/
XDME
/
Src
/
search.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-09-26
|
11KB
|
479 lines
/******************************************************************************
MODUL
search.c
DESCRIPTION
Inherits all the search/replace stuff for DME
NOTES
BUGS
TODO
EXAMPLES
SEE ALSO
INDEX
HISTORY
28. May 1992 ada created
******************************************************************************/
/* Includes */
#include "defs.h"
#define MYDEBUG 0
#include <debug.h>
/* Globale Variable */
/* Interne Defines & Strukturen */
/* Interne Variable */
/*static*/ UBYTE Fstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
/*static*/ UBYTE Rstr[MAXLINELEN]; /* PATCH_NULL - commented out for spcvars */
static char Srch_sign;
static char Doreplace;
/* Interne Prototypes */
Prototype void do_findstr (void);
Prototype void do_findr (void);
Prototype void do_find (void);
Prototype void do_replace (void);
Prototype void search_operation (void);
/*****************************************************************************
NAME
do_findstr
PARAMETER
av[0] "find" or "replace"
av[1] string to find or replace-string
DESCRIPTION
Copies the search/replace-string to the internal buffer.
******************************************************************************/
void do_findstr (void)
{
if (av[0][0] == 'f') /* Check command name */
strcpy(Fstr, av[1]); /* "find" */
else
strcpy(Rstr, av[1]); /* "replace" */
} /* do_findstr */
/*****************************************************************************
NAME
do_findr
PARAMETER
av[0] "findr", "nextr" or "prevr"
av[1] find-string
av[2] replace-string
DESCRIPTION
Starts one find/replace-operation with both search- and replace-string
as arguments.
******************************************************************************/
void do_findr (void)
{
Doreplace = 1; /* Really replace */
Srch_sign = 1; /* Search to EOF */
switch (*av[0])
{
case 'f':
strcpy(Fstr, av[1]); /* Set strings for "findr" */
strcpy(Rstr, av[2]);
break;
case 'p':
Srch_sign = -1; /* Search reverse */
break;
}
search_operation(); /* Start search */
} /* do_findr */
/*****************************************************************************
NAME
do_find
PARAMETER
av[0] "find", "next" or "prev"
av[1] find-string if av[0] == find
DESCRIPTION
Looks for a new string or searches forwards/backwars for the old one.
******************************************************************************/
void do_find (void)
{
Doreplace = 0; /* Don't replace */
Srch_sign = 1;
switch(av[0][0])
{
case 'f': /* Find: new string */
strcpy(Fstr, av[1]);
break;
case 'p': /* Search reverse */
Srch_sign = -1;
break;
}
search_operation ();
} /* do_find */
/*****************************************************************************
NAME
do_replace
PARAMETER
av[0] "replace"
DESCRIPTION
Substitutes the next strlen(search-string) chars with the rep-string.
This command does no checking ! It always removes strlen(search-
string) chars and the rep-string is always inserted.
******************************************************************************/
void do_replace (void)
{
ULONG rlen;
ULONG flen;
Column col;
rlen = strlen (Rstr);
flen = strlen (Fstr);
text_sync ();
col = Ep->column;
/* Check whether replace-string does fit into the line */
if (rlen > flen && (Clen+rlen-flen) > MAXLINELEN-1)
{
error ("replace:\nLine Too Long");
} else
/* This checks whether the search-pattern does fit into
the current line at the current position !?!?! */
if (Clen >= col+flen)
{
/* Move rest of line. Make enough place for replace-string */
movmem (Current+col+flen, Current+col+rlen, Clen-col-flen+1);
/* copy replace-string */
if (rlen)
movmem (Rstr, Current+col, rlen);
/* correct line-length and position after symbol */
Clen += rlen-flen;
Ep->column += rlen -1; /* one position left since we start
at Ep->column+1 with searching */
if (Clen < 0)
Clen = 0;
if (Ep->column < 0)
Ep->column = 0;
}
/* Check display, since we are not sure, whether the actual
position is visible on the screen */
if (!text_adjust (FALSE))
{
text_sync ();
text_redisplaycurrline ();
}
} /* do_replace */
/******************************************************************************
NAME
search_operation
PARAMETER
Fstr String to look for
Rstr String to replace Fsrt with (if Doreplace != 0)
Doreplace Replace Fstr with Rstr ?
Ep Different fields in this structure
DESCRIPTION
Searches in the text for Fstr and replaces it with Rstr if Doreplace is
true. If Ep->ignorecase is true, the string-search is case-insensitive
else not.
For speed, I did replace the old function with this new one. The
routine works like Boyer-Moore search but I didn't find a good
explanation for it in books. You will find some for searching from the
beginning of a string but none if you try reverse. Sigh.
******************************************************************************/
//#define DEBUG
static UBYTE skip[256]; /* Distance for Boyer-Moore */
void search_operation (void)
{
int flen = strlen(Fstr); /* Length of Search/Replace-String */
// int rlen = strlen(Rstr);
UBYTE * ptr;
WORD j; /* Counter in Search-Pattern */
WORD col; /* actual column */
WORD lin; /* actual line */
UWORD linlen; /* length of actual line */
UWORD test; /* result of case(in)sensitive compare */
ED * ep; /* actual editor */
if (!flen)
{ /* Error if nothing to look for. */
error ("search:\nNo find pattern");
return;
}
/* Note that we do not check for nothing to replace, since the user may
want to erase the full pattern */
text_sync (); /* Save Current */
ep = Ep;
col = ep->column; /* Actual column ... */
lin = ep->line; /* ... and line */
/* initskip() */
memset (skip, flen, 256); /* Normally : Skip full length */
if (Srch_sign > 0)
{ /* Search foreward */
ptr = Fstr;
/* Special: Skip until characters match. NOTE: Don't calc.
skip for the LAST character in Fstr */
for (j=flen-1; j>0; ptr ++, j--)
{
if (ep->config.ignorecase)
{
skip[tolower(*ptr)] = j;
skip[toupper(*ptr)] = j;
} else
skip[*ptr] = j;
}
ptr = GETTEXT(ep,lin); /* Get line contents ... */
linlen = strlen (ptr); /* ... and its length */
col ++; /* Don't find it if we're already on it */
for (; ep; )
{
for (;;)
{
/* This is the search-loop. Always remeber Boyer-Moore
begins comparing at the end and scans forward ! */
j = flen - 1;
col += flen - 1;
/* Until reached beginning of search-string or EOL */
while (col < linlen)
{
/* if both are equal (case(in)sensitive) */
if (ep->config.ignorecase)
test = (tolower (ptr[col]) == tolower (Fstr[j]));
else
test = (ptr[col] == Fstr[j]);
if (test)
{
if (!j) /* Full Match */
goto found;
col --; /* Next position */
j --;
} else
{ /* Determine skip-length */
if (flen-j >= skip[ptr[col]])
col += flen - j; /* length of match */
else
col += skip[ptr[col]]; /* Adjust to char. */
j = flen - 1; /* Restart j */
} /* Compare */
} /* while in line */
lin ++;
if (lin >= ep->lines)
break;
ptr = GETTEXT(ep,lin); /* Contents and Length */
linlen = strlen (ptr);
col = 0;
} /* while in text */
if (!globalflags.global_search)
break;
if (ep = (ED *)GetSucc((struct Node *)ep))
{
lin = 0;
ptr = GETTEXT(ep,0); /* Contents and Length */
linlen = strlen (ptr);
col = 0;
}
} /* for all editors */
} else
{ /* Search backward */
/* Special: Skip until characters match. Also don't process last char */
for (j=flen-1; j>0; j--)
{
if (ep->config.ignorecase)
{
skip[tolower(Fstr[j])] = j;
skip[toupper(Fstr[j])] = j;
} else
{
skip[Fstr[j]] = j;
}
}
ptr = GETTEXT(ep,lin); /* Get line contents ... */
linlen = strlen (ptr); /* ... and its length */
if (col >= linlen) /* Beyound End-Of-Line ? */
col = linlen;
D(bug("new search\n"));
for (; ep; )
{
for (;;)
{
/* Same as above but reverse */
j = 0;
col -= flen;
while (col >= 0)
{ /* Until BOL */
/* if both are equal (case(in)sensitive) */
if (ep->config.ignorecase)
test = (tolower (ptr[col]) == tolower (Fstr[j]));
else
test = (ptr[col] == Fstr[j]);
D(bug("[%s]\n[%s]\ncol %2ld j %2ld skip %2ld\n", ptr+col, Fstr+j, col, j,
skip[ptr[col]]));
if (test)
{
if (j == flen-1)
{ /* Full Match */
col -= flen - 1;
goto found;
}
col ++; /* Next position */
j ++;
} else
{ /* Determine skip-length */
j += j;
if (j >= skip[ptr[col]])
{
col -= j; /* Skip back j chars to beginning of
search and j chars to next start */
} else
{
col -= skip[ptr[col]]; /* Adjust to char. */
}
j = 0; /* Restart j */
} /* Compare */
} /* while in line */
/* Prev. line */
if (!lin) /* Stop on 1. line */
break;
lin --;
D(bug("new line\n"));
ptr = GETTEXT(ep,lin); /* Contents and Length */
linlen = strlen (ptr);
/* Last char. */
col = linlen;
} /* while in text */
if (!globalflags.global_search)
break;
if (ep = (ED *)GetPred((struct Node *)ep))
{
lin = ep->lines - 1;
ptr = GETTEXT(ep,lin);
col = linlen = strlen (ptr);
}
} /* for all editors */
} /* if foreward/backward */
warn ("Pattern `%s' Not Found", Fstr);
globalflags.Abortcommand = 1;
return;
found:
if (ep != Ep)
{
switch_ed (ep);
if (ep->iconmode)
{
uniconify ();
} else
{
/* Make window active */
WindowToFront (ep->win);
ActivateWindow (ep->win);
set_window_params ();
window_title ();
}
}
ep->line = lin; /* Set Position */
ep->column = col;
text_load (); /* Copy Line into Current */
if (Doreplace)
do_replace ();
else
text_adjust (FALSE);
} /* search_operation */
/******************************************************************************
***** ENDE search.c
******************************************************************************/